﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace OpenGL
{
	public delegate double TextCharEquation(int row, int col);
	public class GLText : GL
	{
		public static Dictionary<char, int> CharReplace = new Dictionary<char, int>();
		static bool dict = false;
		void MakeDict()
		{
			CharReplace.Add('ő', 256);
			CharReplace.Add('ű', 257);
		}
		const int CELL_SIZE = 32;
		const int TXT_SIZE = (CELL_SIZE << 4) + CELL_SIZE * 1;
		const int FONT_SIZE = CELL_SIZE / 4 * 3;

		GLTexture T;
		public GLText()
		{
			if (!dict)
			{
				dict = true;
				MakeDict();
			}
		}
		public GLText(String FontName)
			: this()
		{
			Bitmap B = new Bitmap(TXT_SIZE, TXT_SIZE);
			Graphics G = Graphics.FromImage(B);
			G.Clear(Color.Black);

			Font F = new Font(FontName, FONT_SIZE);

			RectangleF Layout = new RectangleF();
			Layout.Size = new SizeF(CELL_SIZE, CELL_SIZE);
			StringFormat SF = StringFormat.GenericDefault;
			SF.Alignment = StringAlignment.Center;
			SF.LineAlignment = StringAlignment.Center;
			for (int i = 0; i < 16; i++)
				for (int j = 0; j < 16; j++)
				{
					Layout.Location = new Point(j * CELL_SIZE, i * CELL_SIZE);
					G.DrawString("" + (char)(i * 16 + j), F, Brushes.White, Layout, SF);
				}
			Layout.Location = new PointF(0, 512);
			G.DrawString("ő", F, Brushes.White, Layout, SF);
			Layout.Location = new PointF(CELL_SIZE, 512);
			G.DrawString("ű", F, Brushes.White, Layout, SF);
			T = new GLTexture(B);
		}
		public void Bind()
		{
			T.Bind();
		}
		public void DrawString(String S, V3D Start, V3D Dir, V3D Line, V3D Up, double fontheight, double fontwidth, StringAlignment Align, StringAlignment LineAlign)
		{
			String[] Rows = S.Split('|');
			V3D LH = Up * (Rows.Length - 1) + Up.Unit * fontheight;
			int NL = 0;
			foreach (var X in Rows)
			{
				V3D RL = Dir * (X.Length - 1) + Dir.Unit * fontwidth;
				V3D Start2 = Start;
				if (Align != StringAlignment.Near)
					Start2 = Start - RL * (Align == StringAlignment.Center ? 0.5 : 1);
				V3D Line2 = V3D.Black;
				if (LineAlign != StringAlignment.Near)
					Line2 = LH * (LineAlign == StringAlignment.Center ? 0.5 : 1);
				DrawLine(X, Start2 - Line2 + Line * NL, Dir, Up, fontheight, fontwidth);
				NL++;
			}
		}

		void DrawLine(String S, V3D Start, V3D Dir, V3D Up, double fontheight, double fontwidth)
		{
			int N = 0;
			foreach (char C in S)
			{
				DrawChar(C, Start + Dir * N, Dir.Unit * fontwidth, Up.Unit * fontheight);
				N++;
			}
		}

		public void DrawString(String S, double X, double Y, double fontsize, double textwidth, StringAlignment Align)
		{
			T.Bind();
			glPushAttrib(GL.GL_ALL_ATTRIB_BITS);
			BlendAlpha();

			int N = 0;
			foreach (String s in S.Split('|'))
			{
				DrawText(s, X, Y + N * fontsize, fontsize, textwidth, Align);
				N++;
			}
			GL.glPopAttrib();
		}
		public void DrawText(String S, double X, double Y, StringAlignment Align)
		{
			DrawText(S, X, Y, 24, 24, Align);
		}

		//Bitmap B = new Bitmap(1, 1);
		Graphics G = Graphics.FromImage(new Bitmap(1, 1));

		public void DrawText(String S, double X, double Y, double fontsize, double textwidth, StringAlignment Align)
		{
			double D = Align == StringAlignment.Near ? 0 : Align == StringAlignment.Center ? 0.5 : 1;
			double startx = X - D * ((S.Length - 1) * textwidth + fontsize);
			int N = 0;
			double LX = startx;
			foreach (char C in S)
			{
				char c = C;
				if (CharReplace.ContainsKey(C))
					c = (char)CharReplace[C];
				DrawChar(c, fontsize, fontsize, LX, Y, 0, V3D.White, 1);
				//+ textwidth * N
				LX += G.MeasureString("" + C, new Font("Arial", 24)).Width / 48 * fontsize;
				N++;
			}
		}
		public void DrawChar(int ch, double size, double width, double X, double Y, double rot, V3D Color, double fade)
		{
			double S = ((ch % 16) + 1.0 / 32) / 17.0;
			double T = ((ch / 16) + 1.0 / 32) / 17.0;
			double cs = 30.0 / 32 / 17;
			GL.glPushAttrib(GL.GL_ALL_ATTRIB_BITS);
			GL.BlendAlpha();
			GL.glPushMatrix();
			GL.glTranslated(X, Y, 0);
			GL.glRotated(rot, 0, 1, 0);
			GL.glEnable(GL.GL_TEXTURE_2D);
			Bind();
			GL.glBegin(GL.GL_QUADS);
			//GL.glColor4d(Color.X, Color.Y, Color.Z, fade);
			/*
			GL.glTexCoord2d(S, T);
			GL.glVertex3d(-size / 2, -width / 2, 0);
			GL.glTexCoord2d(S + 1 / 16.0, T);
			GL.glVertex3d(size / 2, -width / 2, 0);
			GL.glTexCoord2d(S + 1 / 16.0, T + 1 / 16.0);
			GL.glVertex3d(size / 2, width / 2, 0);
			GL.glTexCoord2d(S, T + 1 / 16.0);
			GL.glVertex3d(-size / 2, size / 2, 0);
			*/
			GL.glTexCoord2d(S, T + cs);
			GL.glVertex3d(0, 0, 0);
			GL.glTexCoord2d(S + cs, T + cs);
			GL.glVertex3d(size, 0, 0);
			GL.glTexCoord2d(S + cs, T);
			GL.glVertex3d(size, width, 0);
			GL.glTexCoord2d(S, T);
			GL.glVertex3d(0, size, 0);

			GL.glEnd();
			GL.glPopMatrix();
			GL.glPopAttrib();
		}

		public void DrawChar(int ch, V3D Pos, V3D Dir, V3D Up)
		{
			double S = ((ch % 16) + 1.0 / 32) / 17.0;
			double T = ((ch / 16) + 1.0 / 32) / 17.0;
			double cs = 30.0 / 32 / 17;
			GL.glPushAttrib(GL.GL_ALL_ATTRIB_BITS);
			GL.glPushMatrix();
			GL.glTrans3D(Pos);
			//GL.glRotated(rot, 0, 1, 0);
			GL.glEnable(GL.GL_TEXTURE_2D);
			Bind();
			GL.glBegin(GL.GL_QUADS);

			GL.glTexCoord2d(S, T + cs);
			GL.glVertex3d(0, 0, 0);
			GL.glTexCoord2d(S + cs, T + cs);
			GL.glV3D(Dir);
			GL.glTexCoord2d(S + cs, T);
			GL.glV3D(Dir + Up);
			GL.glTexCoord2d(S, T);
			GL.glV3D(Up);
			GL.glEnd();
			GL.glPopMatrix();
			GL.glPopAttrib();
		}
	}

	public class TextDisplayer
	{
		GLText T;
		String[] DisplayText;

		//V3D Start, Base, Row;
		StringAlignment Align;
		public TextDisplayer(String S, V3D pos, V3D basedir, V3D rowdir, StringAlignment align)
		{
			SetText(S);
			Align = align;
		}
		public void SetText(String S)
		{
			DisplayText = S.Split('\n');
		}
		public void GenerateFont(String FontName)
		{
			T = new GLText(FontName);
		}
		double fade = 0;
		public void Process(double dt)
		{
			fade += dt;
		}

		public void DrawText(String S, int size, V3D Pos, V3D BaseDir, V3D Row, double width, TextCharEquation fader)
		{
			String[] X = S.Split('\n');
			for (int i = 0; i < X.Length; i++)
				for (int j = 0; j < X[i].Length; j++)
				{
					V3D CharPos = Pos + (Row) * i + (BaseDir * j);
					T.DrawChar(X[i][j], size, width, CharPos.X, CharPos.Y, 0, V3D.White, fader(i, j));
				}
		}
	}
}